/**
 * @author Daniel "Monty" Monteiro
 * */

package br.odb.bzk3.android;

import java.io.InputStream;
import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import br.odb.bzk3.geometry.GameActor;
import br.odb.libscene.Actor;
import br.odb.libscene.Sector;
import br.odb.utils.Utils;

public class EngineView extends GLSurfaceView implements Runnable,
		VirtualPadClient, OnTouchListener  {
	// ------------------------------------------------------------------------------------------------------------
	// <android stuff>
	// WTF?
	private static final String LOG_TAG = EngineView.class.getSimpleName();
	private static final long INTERVAL = 50;
	private GLESRenderer renderer;
	private boolean running = true;
	public static boolean loaded = false;
	// </android stuff>

	// <willie stuff>
	ArrayList< Actor > people;
	GameWorld world;
	public int angle;
	
	public GameActor cameraActor;
	public int gotoScreen;
	private boolean[] keyMap;
	public Thread updater;
//	MediaPlayer mp;
	// ------------------------------------------------------------------------------------------------------------
	public GameWorld getWorld() {
		return world;
	}

	// ------------------------------------------------------------------------------------------------------------
	public String toString() {
		return world.toString() + "\n" + renderer.toString();
	}

	
	
	// ------------------------------------------------------------------------------------------------------------
	public EngineView( Context context ) {
		super( context );
		people = new ArrayList< Actor>();
		keyMap = new boolean[9];


		renderer = new GLESRenderer();
		// translations table - used to speed up and improve usability
		// add one more, to help with overlapping angles
		
		setFocusable(true);
		setClickable(true);
		setLongClickable(true);
		setFocusableInTouchMode(true);
		requestFocus();		
		setRenderer(renderer);
		setOnTouchListener( this );
	}
	

	
	public void loadComplete() {
		cameraActor = (GameActor) people.get(0);
		renderer.setCurrentCamera( cameraActor );
		for (int c = 0; c < people.size(); c++) {
			placeActor((GameActor) people.get(c), people.get(c).currentSector);
			renderer.addToScene( (GameActor)people.get(c));
		}

		for (int c = 1; c < world.getTotalSectors(); c++)
			renderer.addToScene( (GameSector) world.getSector(c) );

		renderer.buildScene();
		updater = new Thread( this );
		updater.start();
	}
	
	public void load( InputStream data) {

		gotoScreen = -1;
		// <willie stuff>
		angle = 0;
//		Uri uri = Uri.parse("http://jovemnerd.ig.com.br/podpress_trac/web/51269/0/nerdcast_268_old_vs_new_games.mp3");
//		mp = MediaPlayer.create( context, uri);
		
	

		// </willie stuff>

		// <android stuff>


		renderer.setAngle(angle * 22.5f);

		Thread monitorThread = new Thread(this);
		monitorThread.setPriority(Thread.MIN_PRIORITY);
		monitorThread.start();
		// </android stuff>

		// <init>
	

		try {
			InputStream is = getResources().openRawResource(R.raw.riffle);
			int entries = is.read();
			byte[] bytes = new byte[10];
			Triangle t;
			int range = Byte.MAX_VALUE - Byte.MIN_VALUE;
			for (int c = 0; c < entries; ++c) {

				is.read(bytes);

				t = new Triangle();

				t.a = (bytes[0] + (-Byte.MIN_VALUE));
				t.r = (bytes[1] + (-Byte.MIN_VALUE));
				t.g = (bytes[2] + (-Byte.MIN_VALUE));
				t.b = (bytes[3] + (-Byte.MIN_VALUE));

				t.x0 = -0.5f + (((bytes[4] + (-Byte.MIN_VALUE)) * 569) / range)
						/ (569.0f / 1.2f);
				t.y0 = 0.5f - (((bytes[5] + (-Byte.MIN_VALUE)) * 270) / range) / 270.0f;
				// Log.d("BZK3","x0: " + t.x0 + " y0: " + t.y0 );
				t.x1 = -0.5f + (((bytes[6] + (-Byte.MIN_VALUE)) * 569) / range)
						/ (569.0f / 1.2f);
				t.y1 = 0.5f - (((bytes[7] + (-Byte.MIN_VALUE)) * 270) / range) / 270.0f;

				t.x2 = -0.5f + (((bytes[8] + (-Byte.MIN_VALUE)) * 569) / range)
						/ (569.0f / 1.2f);
				t.y2 = 0.5f - (((bytes[9] + (-Byte.MIN_VALUE)) * 270) / range) / 270.0f;

				renderer.shapes.add(t);
				t.flatten();
				t.init();
			}
			world = new GameWorld(data, people);
			loaded = true;
		} catch (Exception e) {

		}
		
		// </init>
	}

	// ------------------------------------------------------------------------------------------------------------
	public void placeActor(GameActor actor, int sectorId ) {
		GameSector sector = (GameSector) world.getSector( sectorId );
		actor.moveTo( sector.getCenter() );
		actor.setCurrentSector( sectorId );
		ObjMesh obj = new ObjMesh();
		obj.internalize( getResources().openRawResource( R.raw.ghost ) );
		actor.setMesh( obj );
		obj.moveTo( actor.startPoint );
	}

	// ------------------------------------------------------------------------------------------------------------
	public boolean onTouchEvent(final MotionEvent event) {
		return true;
	}

	// ------------------------------------------------------------------------------------------------------------
	@Override
	public void run() {

		while (running) {
			if ( !loaded )
				continue;
			
			try {
				Thread.sleep(INTERVAL);
			} catch (Exception e) {

			}
			
			GameSector sector;
			GameActor actor;
			
			for ( int c = 0; c < people.size(); ++c ) {
				actor = (GameActor) people.get( c );
				
				//tmp
				if ( c != 0 )
					actor.tick();
				
				sector = (GameSector) world.getSector( actor.currentSector );
				
				int candidate = sector.locateEscapePlane( actor.startPoint );
				
				while ( candidate != 100 ) {
					if ( sector.getLink( candidate ) != Sector.NO_LINK ) {
						sector = (GameSector) world.getSector( sector.getLink( candidate ) );
						candidate = sector.locateEscapePlane( actor.startPoint );				
					} else {
						candidate = 100;
						actor.undo();
					}
				}
				actor.setCurrentSector( sector.getId() );
				
				
//				if ( sector.locateEscapePlane( actor.startPoint ) != 100 ) {
//
////					Log.d("BZK3", "link:" + sector.locateEscapePlane( actor.startPoint ) + " sector:" + actor.Sector + " pos:" + actor.startPoint.toString() );
//					
//					if (sector.GetLink(sector.locateEscapePlane( actor.startPoint ) ) != 0 ) {
//						actor.Sector = sector.GetLink( sector.locateEscapePlane( actor.startPoint ) );
//					} else {
//						actor.undo();
//					}
//				}				
			}
			
		}

	}

	// ------------------------------------------------------------------------------------------------------------


	public boolean onKeyUp(int keyCode, KeyEvent event) {
		
//		if (keyCode == KeyEvent.KEYCODE_Z) {
//			mp.start();
//		}
//		
//		if (keyCode == KeyEvent.KEYCODE_X) {
//			mp.pause();
//		}
//		
//		if (keyCode == KeyEvent.KEYCODE_C) {
//			mp.stop();
//		}

		
		
		if (keyCode == KeyEvent.KEYCODE_W || keyCode == KeyEvent.KEYCODE_DPAD_UP ) {
			keyMap[VirtualPad.KB_UP] = false;
		}
		if (keyCode == KeyEvent.KEYCODE_S || keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
			keyMap[VirtualPad.KB_DOWN] = false;
		}
		if (keyCode == KeyEvent.KEYCODE_Q || keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
			keyMap[VirtualPad.KB_LEFT] = false;
		}
		if (keyCode == KeyEvent.KEYCODE_E || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
			keyMap[VirtualPad.KB_RIGHT] = false;
		}
		if (keyCode == KeyEvent.KEYCODE_O) {
			keyMap[VirtualPad.KB_FIRE2] = false;
		}
		if (keyCode == KeyEvent.KEYCODE_L) {
			keyMap[VirtualPad.KB_FIRE3] = false;
		}

		if (keyCode == KeyEvent.KEYCODE_BACK)
			( ( Activity ) getContext() ).finish();

		handleKeys(keyMap);
		return true;
	}

	// ------------------------------------------------------------------------------------------------------------
	public boolean onKeyDown(int keyCode, KeyEvent event) {

		if (keyCode == KeyEvent.KEYCODE_W || keyCode == KeyEvent.KEYCODE_DPAD_UP ) {
			keyMap[VirtualPad.KB_UP] = true;
		}
		if (keyCode == KeyEvent.KEYCODE_S || keyCode == KeyEvent.KEYCODE_DPAD_DOWN ) {
			keyMap[VirtualPad.KB_DOWN] = true;
		}
		if (keyCode == KeyEvent.KEYCODE_Q || keyCode == KeyEvent.KEYCODE_DPAD_LEFT ) {
			keyMap[VirtualPad.KB_LEFT] = true;
		}
		if (keyCode == KeyEvent.KEYCODE_E || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ) {
			keyMap[VirtualPad.KB_RIGHT] = true;
		}
		if (keyCode == KeyEvent.KEYCODE_O) {
			keyMap[VirtualPad.KB_FIRE2] = true;
		}
		if (keyCode == KeyEvent.KEYCODE_L) {
			keyMap[VirtualPad.KB_FIRE3] = true;
		}

		if (keyCode == KeyEvent.KEYCODE_BACK)
			System.exit(0);

		handleKeys(keyMap);

		return true;
	}

	// ------------------------------------------------------------------------------------------------------------

	@Override
	public void handleKeys(boolean[] keymap) {
		float x, y, z;
		x = 0;
		y = 0;
		z = 0;
		if (keymap[VirtualPad.KB_UP]) {
			
			x += Utils.getTranslationForOctant( angle ).iX;
			z -= Utils.getTranslationForOctant( angle ).iY;

		}

		if (keymap[VirtualPad.KB_DOWN]) {
			x -= Utils.getTranslationForOctant( angle ).iX;
			z += Utils.getTranslationForOctant( angle ).iY;

		}

		if (keymap[VirtualPad.KB_LEFT]) {
			this.angle--;
			renderer.setAngle(angle * 22.5f);
		}

		if (keymap[VirtualPad.KB_RIGHT]) {
			this.angle++;
			renderer.setAngle(angle * 22.5f);
		}

		if (keymap[VirtualPad.KB_FIRE3]) {
			y -= 1;

		}

		if (keymap[VirtualPad.KB_FIRE2]) {
			y += 1;
		}

		cameraActor.move( x, y, z );
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		int width = getWidth();
		if ( event.getX() < width / 3 ) {
			keyMap[ VirtualPad.KB_LEFT ] = event.getAction() == MotionEvent.ACTION_DOWN;
		} else if ( event.getX() > ( width * 2 ) / 3  ) {
			keyMap[ VirtualPad.KB_RIGHT ] = event.getAction() == MotionEvent.ACTION_DOWN;
		} else {
			if ( event.getY() < getHeight() / 2 ) {
				keyMap[ VirtualPad.KB_UP ] = event.getAction() == MotionEvent.ACTION_DOWN;
			} else {
				keyMap[ VirtualPad.KB_DOWN ] = event.getAction() == MotionEvent.ACTION_DOWN;
			}			
		}
		
		handleKeys(keyMap);
		return true;
	}
}
